package main

import(
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"github.com/hyperledger/fabric-contract-api-go/contractapi"
	"bytes"
)

//定义合约
type TradingContract struct{
	contractapi.Contract
}

//定义用户
type User struct{
	ID       string    `json:"ID"`
    Token    float32   `json:"Token"`
	Inputs   float32   `json:"Inputs"`
	Outputs  float32   `json:"Outputs"`
	Total    float32   `json:"Total"`
}

//初始化 将用户数据存入账本
func(s *TradingContract) InitUser(ctx contractapi.TransactionContextInterface)error{
	users := [] User{
		{ID:"user0",   Token:100.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user1",   Token:120.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user2",   Token:115.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user3",   Token:117.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user4",   Token:148.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user5",   Token:135.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user6",   Token:140.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user7",   Token:115.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user8",   Token:127.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user9",   Token:128.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user10",  Token:109.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user11",  Token:120.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user12",  Token:111.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user13",  Token:117.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user14",  Token:142.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user15",  Token:135.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user16",  Token:102.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user17",  Token:145.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user18",  Token:122.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user19",  Token:118.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user20",  Token:150.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user21",  Token:132.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user22",  Token:116.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user23",  Token:107.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user24",  Token:148.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user25",  Token:115.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user26",  Token:144.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user27",  Token:127.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user28",  Token:106.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
		{ID:"user29",  Token:133.0, Inputs:0.0, Outputs:0.0, Orders:[] ,Total: 100.0},
	}

	for _, user := range users {
		userJSON, err := json.Marshal(user) 
		if err != nil {
			return err
		}
	
		err = ctx.GetStub().PutState(user.ID, userJSON)
		if err != nil {
			return fmt.Errorf("failed to put to world state. %v", err)
		}
	}
	
	  return nil
}

//判断用户是否存在 
//参数：id string
func (s *TradingContract) UserExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
	userJSON, err := ctx.GetStub().GetState(id)
	if err != nil {
	  return false, fmt.Errorf("failed to read from world state: %v", err)
	}
  
	return userJSON != nil, nil
  
}

//若用户不存在，则创建用户
//参数：id string,token float32,inputs float32,outputs float32,total float 32
func (s *TradingContract) CreateUser(ctx contractapi.TransactionContextInterface, id string, token float32,inputs float32,outputs float32,total float32) error {
	exists, err := s.UserExists(ctx, id)
	if err != nil {
		return err
	}
	if exists {
		return fmt.Errorf("the user %s already exists", id)
	}

	user := User{
		ID:         id,
		Token:      token,
		Inputs:     inputs,
		Outputs:    outputs,
		Total:      total,
	}
	userJSON, err := json.Marshal(user)
	if err != nil {
		return err
	}

	return ctx.GetStub().PutState(id, userJSON)
}

//读取用户信息
//参数：id string
func (s *TradingContract) ReadUser(ctx contractapi.TransactionContextInterface, id string) (*User, error){
	userJSON, err := ctx.GetStub().GetState(id)
	if err != nil {
		return nil, fmt.Errorf("failed to read from world state: %v", err)
	}
	if userJSON == nil {
		return nil, fmt.Errorf("the user %s does not exist", id)
	}

	var user User
	err = json.Unmarshal(userJSON, &user)
	if err != nil {
		return nil, err
	}

	return &user, nil
}

//删除用户
//参数：id srting
func (s *TradingContract) DeleteUser(ctx contractapi.TransactionContextInterface, id string) error {
	exists, err := s.UserExists(ctx, id)
	if err != nil {
		return err
	}
	if !exists {
		return fmt.Errorf("the user %s does not exist", id)
	}

	return ctx.GetStub().DelState(id)
}

//查询所有用户
func (s *TradingContract) GetAllUser(ctx contractapi.TransactionContextInterface) ([]*User, error) {
	resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
	if err != nil {
		return nil, err
	}
	defer resultsIterator.Close()

	var users []*User
	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			return nil, err
		}

		var user User
		err = json.Unmarshal(queryResponse.Value, &user)
		if err != nil {
			return nil, err
		}
		users = append(users, &user)
	}

	return users, nil
}

//扣钱
//参数：买家id string, price flaot32, amount float32
func (s *TradingContract) Deduct(ctx contractapi.TransactionContextInterface, id string, price float32, amount float32) error {
	exists, err := s.UserExists(ctx, id)
    if err != nil {
        return err
    }
    if !exists {
        return fmt.Errorf("the user %s does not exist", id)
    }
	userJSON1, err := ctx.GetStub().GetState(id)

	var user User
	err = json.Unmarshal(userJSON1, &user)
	if err != nil {
		return err
	}
	user.Token = user.Token-price*amount

	userJSON2, err := json.Marshal(user)
	if err != nil {
	  return err
	}
	fmt.Println("扣钱成功,余额：",user.Token)
	return ctx.GetStub().PutState(id, userJSON2)
  }


//转账 
//参数：卖家id string, 单价price float32, 数量amount float32
func (s *TradingContract) Transfer(ctx contractapi.TransactionContextInterface, id string, price float32, amount float32) error {
	fmt.Panicf
	fmt.Printf("交易总价:%f",price*amount)
	exists, err := s.UserExists(ctx, id)
    if err != nil {
        return err
    }
    if !exists {
        return fmt.Errorf("the user %s does not exist", id)
    }
	userJSON, err := ctx.GetStub().GetState(id)

	var user User
	err = json.Unmarshal(userJSON, &user)
	if err != nil {
		return err
	}
	user.Token = user.Token + price*amount

	updatedUserJSON, err := json.Marshal(user)
	if err != nil {
	  return err
	}
  
	return ctx.GetStub().PutState(id, updatedUserJSON)
  }

//调用验证接口 验证充电
//参数：id string,inputs float32,outputs float32
func(s *TradingContract) GetCheckRequset(id string,inputs float32,outputs float32)error{
	CheckUrl := "http://192.168.31.11:5000/trading/F0_house_A0" 
	
	// 要传的数据（id）
    requestData :=[]map[string]string{
        {"id":    id },
    }
    requestBody, err := json.Marshal(requestData)
    if err != nil {
        fmt.Println("请求数据转换失败：", err)
        return err
    }

    // 发送 POST 请求
    resp, err := http.Post(CheckUrl, "application/json", bytes.NewBuffer(requestBody))
    if err != nil {
        fmt.Println("请求接口失败：", err)
        return err
    }
    defer resp.Body.Close()

    // 解析响应数据
    var responseData map[string]interface{}
    err = json.NewDecoder(resp.Body).Decode(&responseData)
    if err != nil {
        fmt.Println("解析响应数据失败：", err)
        return err
    }

    // 输出响应结果（返回充放电量）
    fmt.Println(responseData)

	//验证充放电结果
	if responseData["inputs"]==inputs||responseData["inputs"]==outputs{
		fmt.Println("验证充放电成功")
	} else{
		fmt.Println("验证充放电失败")
		return fmt.Errorf("验证充放电失败")
	}
	return nil
}



//合约入口主函数
func main() {
	chaincode, err := contractapi.NewChaincode(&TradingContract{})
	if err != nil {
	  log.Panicf("Error creating trading chaincode: %v", err)
	}
  
	if err := chaincode.Start(); err != nil {
	  log.Panicf("Error starting trading chaincode: %v", err)
	}
  }